// 本hpp用于 <<封装自己的线程相关接口，给线程添加更多属性>> 方便测试查看
// 可用于学习，不可进行抄袭、转载、更改等对原创知识有害的操作，如需转载分享，请标明出处

#pragma once
#include <pthread.h>
#include <string>
#include <functional>

// 形同于：typedef std::function<void*(void*)> func_t
template <class R>
using func_t = std::function<R()>;

template <class R>
class Thread
{
public:
    Thread(func_t<R> func)
        : _thread(0)
        , _thread_name()
        , _attr(pthread_attr_t())
        , _istunning(false)
        , _func(func)
    {
        _thread_name = Create_Thread_Name();
    }

    // 开始让线程执行对应方法
    void Start()
    {
        _istunning = true;
        // 前两个都为输出型参数，可以得到线程ID与属性集
        pthread_create(&_thread, &_attr, Function, (void *)this);
    }

    // 等待线程
    void Join()
    {
        // 可以得到thread执行完函数方法的返回值信息
        pthread_join(_thread, &_return_message);
        _istunning = false;
    }
    
    //分离线程
    void Detach()
    {
        pthread_detach(pthread_self());
    }
    
    //拿到线程的成员变量
    pthread_t tid() {return _thread;}
    std::string& name() {return _thread_name;}
    const pthread_attr_t& attr() {return _attr;}
    bool Isrunning() {return _istunning;}
    R& re_message() {return reinterpret_cast<R>(_return_message);}

private:
    pthread_t _thread;          // 线程ID
    std::string _thread_name;   // 线程名字 
    const pthread_attr_t _attr; // 线程属性集
    bool _istunning;            // 线程是否运行
    void *_return_message;      // 线程执行完对应方法的返回值信息
    func_t<R> _func;         // 线程执行的函数方法

    // 这么写Functuon的原因:我们可以通过伪造一个void*(*)(void*)类型的函数
    // 但是在函数内部可以用来回调我们在main.cc中的函数方法
    // 通过第二个参数传this指针，可以找到_func和_arg
    // 至此可以让我们成功回调我们自定义的函数方法
    static void *Function(void *arg)
    {
        Thread<R> *pThread = static_cast<Thread<R> *>(arg);
        return reinterpret_cast<void*>(pThread->_func());
    }

    std::string Create_Thread_Name()
    {
        std::string name = "thread-";
        static int i = 1; //定义一个局部的静态变量，作用域是该函数内有效，生命周期为全局的
        name += std::to_string(i++);
        return name;
    }
};